﻿using jvm.classfile.attributeinfo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/**
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
 */
namespace jvm.classfile
{
    class ClassFile
    {
        public ushort minor_version;
        public ushort major_version;
        public ConstantPool constantPool;
        public ushort access_flags;
        public ushort this_class;
        public ushort super_class;
        public ushort[] interfaces;
        public JMemberInfo[] fields;
        public JMemberInfo[] methods;
        public AttributeInfo[] attributes;

        public void Parse(byte[] classdata)
        {
            ClassReader reader = new ClassReader(classdata);
            reader.ReadUint(); // magic
            minor_version = reader.ReadUshort();
            major_version = reader.ReadUshort();
            ushort constant_pool_count = reader.ReadUshort();
            constantPool = new ConstantPool();
            constantPool.Read(constant_pool_count , reader);
            access_flags = reader.ReadUshort();
            this_class = reader.ReadUshort();
            super_class = reader.ReadUshort();
            ushort interfaces_count = reader.ReadUshort();
            interfaces = new ushort[interfaces_count];
            for (int i = 0; i < interfaces_count; i++)
            {
                interfaces[i] = reader.ReadUshort();
            }

            ushort fields_count = reader.ReadUshort();
            fields = new JMemberInfo[fields_count];
            for (int i = 0; i < fields_count; i++)
            {
                fields[i] = new JMemberInfo();
                fields[i].pool = constantPool;
                fields[i].Read(reader);
            }
            ushort methods_count = reader.ReadUshort();
            methods = new JMemberInfo[methods_count];
            for (int i = 0; i < methods_count; i++)
            {
                methods[i] = new JMemberInfo();
                methods[i].pool = constantPool;
                methods[i].Read(reader);
            }
            ushort attributes_count = reader.ReadUshort();
            attributes = new AttributeInfo[attributes_count];
            for (int i = 0; i < attributes_count; i++)
            {
                attributes[i] = AttrFactory.Create(reader, constantPool);

                attributes[i].Read(reader);
            }
        }

        public string ClassName() {
            return constantPool.GetClassName(this_class);
        }

        public string SuperClassName()
        {
            if (super_class > 0)
            {
                return constantPool.GetClassName(super_class);
            }
            return "";
        }

        public string[] InterfaceNames()   {
            string[] interfaceNames = new string[interfaces.Length];
            for (int i = 0; i < interfaces.Length; i++)
            {
                interfaceNames[i] = constantPool.GetClassName(interfaces[i]);
            }
            return interfaceNames;
        }

        public SourceFileAttribute SourceFileAttribute
        {
            get{

                foreach (AttributeInfo attributeInfo in attributes)
                {
                    if (attributeInfo.GetType() == typeof(SourceFileAttribute))
                    {
                        return (SourceFileAttribute)attributeInfo;
                    }
                }
                return null;
            }
        }
    }
}
